package com.filyar.htyd.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.filyar.htyd.entity.*;
import com.filyar.htyd.entity.po.PersonSchedulePo;
import com.filyar.htyd.entity.vo.PersonShiftCountVo;
import com.filyar.htyd.entity.vo.PersonStatisticsVo;
import com.filyar.htyd.entity.vo.ScheduleVo;
import com.filyar.htyd.mapper.*;
import com.filyar.htyd.service.IScheduleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author filyar
 * @e-mail root@filyar.com
 * @since 2024-08-29
 */
@Service
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements IScheduleService {

    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private PersonMapper personMapper;
    @Resource
    private DayTypeMapper dayTypeMapper;
    @Resource
    private DayMapper dayMapper;
    @Resource
    private ShiftHistoryMapper shiftHistoryMapper;

    private final static List<Integer> SPECIAL_DAY_TYPE = Arrays.asList(1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
    private final static List<Integer> SPECIAL_DAY_TYPE_WITH_FRIDAY = Arrays.asList(1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
    private final static List<Integer> ORIGINAL_DAY_TYPE = Arrays.asList(2, 3, 4, 5);
    private final static List<Integer> ORIGINAL_DAY_TYPE_WITH_FRIDAY = Arrays.asList(2, 3, 4, 5, 6);

    @Override
    public List<ScheduleVo> generate(String date) {
        List<Schedule> schedules;
        List<Schedule> specialDays = new ArrayList<>();
        List<Schedule> originalDays = new ArrayList<>();
        List<Person> persons = personMapper.selectList(null);
        List<DayType> dayTypes = dayTypeMapper.selectList(null);
        //获取月份的每一天的对应的日子类型集合
        DateTime parse = DateUtil.parse(date, "yyyy-MM");
        DateTime beginOfMonth = DateUtil.beginOfMonth(parse);
        DateTime endOfMonth = DateUtil.endOfMonth(parse);
        //判断是否已经生成过
        if(CollUtil.isNotEmpty(scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                .between(Schedule::getShiftDate, beginOfMonth, endOfMonth)))){
            return null;
        }
        List<Day> currentMonthDays = dayMapper.selectList(new LambdaQueryWrapper<Day>().between(Day::getDate, beginOfMonth, endOfMonth));
        String strEndOfMonth = DateUtil.format(endOfMonth, "yyyy-MM-dd");
        String partOfDay = strEndOfMonth.substring(strEndOfMonth.lastIndexOf("-") + 1);
        String partOfYearAndMonth = strEndOfMonth.substring(0, strEndOfMonth.lastIndexOf("-") + 1);
        int lastDay = NumberUtil.parseInt(partOfDay);
        for (int i = 0; i < lastDay; i++) {
            String strDay = partOfYearAndMonth + (i + 1);
            DateTime currentDay = DateUtil.parse(strDay, "yyyy-MM-dd");
            //比较两个时间
            //在currentMonthDays中查询日子对应的dayType
            Day day = currentMonthDays.stream().filter(d -> DateUtil.isSameDay(d.getDate(), currentDay)).findFirst().get();
            Integer dayTypeId = day.getDayTypeId();
            Schedule shift1 = new Schedule();
            Schedule shift2 = new Schedule();
            Schedule shift3 = new Schedule();
            shift1.setShiftDate(currentDay);
            shift1.setShiftId(1);
            shift1.setDayTypeId(dayTypeId);

            shift2.setShiftDate(currentDay);
            shift2.setShiftId(2);
            shift2.setDayTypeId(dayTypeId);

            shift3.setShiftDate(currentDay);
            shift3.setShiftId(3);
            shift3.setDayTypeId(dayTypeId);

            if (dayTypeId > 1 && dayTypeId < 6) {
                originalDays.add(shift1);
                originalDays.add(shift2);
                originalDays.add(shift3);
            } else if (dayTypeId == 6) {
                specialDays.add(shift3);
                originalDays.add(shift1);
                originalDays.add(shift2);
            } else {
                specialDays.add(shift1);
                specialDays.add(shift2);
                specialDays.add(shift3);
            }
        }

        for (Schedule specialDay : specialDays) {
            Schedule schedule = new Schedule();
            PersonSchedulePo personSchedulePo = null;
            if (specialDay.getShiftId() == 3) {
                //从male集合中获取一位添加id到schedule
                personSchedulePo = scheduleMapper.selectPersonForSpecialDay(1, SPECIAL_DAY_TYPE_WITH_FRIDAY);
            }else{
                //从female集合中获取一位女性添加id到schedule
                personSchedulePo = scheduleMapper.selectPersonForSpecialDay(2, SPECIAL_DAY_TYPE);
            }
            specialDay.setPersonId(personSchedulePo.getPersonId());
            schedule.setDayTypeId(specialDay.getDayTypeId());
            schedule.setPersonId(personSchedulePo.getPersonId());
            schedule.setShiftId(specialDay.getShiftId());
            schedule.setShiftDate(specialDay.getShiftDate());
            scheduleMapper.insert(schedule);
        }
        for (Schedule originalDay : originalDays) {
            Schedule schedule = new Schedule();
            PersonSchedulePo personSchedulePo = new PersonSchedulePo();
            if (originalDay.getShiftId() == 3) {
                personSchedulePo = scheduleMapper.selectPersonForSpecialDay(1, ORIGINAL_DAY_TYPE);

            } else {
                personSchedulePo = scheduleMapper.selectPersonForSpecialDay(2, ORIGINAL_DAY_TYPE_WITH_FRIDAY);
            }
            originalDay.setPersonId(personSchedulePo.getPersonId());
            schedule.setDayTypeId(originalDay.getDayTypeId());
            schedule.setPersonId(personSchedulePo.getPersonId());
            schedule.setShiftId(originalDay.getShiftId());
            schedule.setShiftDate(originalDay.getShiftDate());
            scheduleMapper.insert(schedule);
        }

        //把两个list合到一起
        schedules = Stream.concat(specialDays.stream(), originalDays.stream()).collect(Collectors.toList());
        return getScheduleVos(schedules, persons, dayTypes);
    }

    @Override
    public List<PersonShiftCountVo> getPersonList(Integer dayTypeId, Integer gender) {
        List<Integer> dayTypes = null;
        if (gender == 1) {
            if (dayTypeId > 1 && dayTypeId < 6) {
                dayTypes = ORIGINAL_DAY_TYPE;
            } else {
                dayTypes = SPECIAL_DAY_TYPE_WITH_FRIDAY;
            }
        } else {
            if (dayTypeId > 1 && dayTypeId < 7) {
                dayTypes = ORIGINAL_DAY_TYPE_WITH_FRIDAY;
            } else {
                dayTypes = SPECIAL_DAY_TYPE;
            }
        }
        return scheduleMapper.selectPersonList(gender, dayTypes);
    }

    @Override
    public List<ScheduleVo> querySchedule(String date) {
        List<Person> persons = personMapper.selectList(null);
        List<DayType> dayTypes = dayTypeMapper.selectList(null);
        DateTime parse = DateUtil.parse(date, "yyyy-MM");
        //获取月份的每一天的对应的日子类型集合
        DateTime beginOfMonth = DateUtil.beginOfMonth(parse);
        DateTime endOfMonth = DateUtil.endOfMonth(parse);
        List<Schedule> schedules = scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                .between(Schedule::getShiftDate, beginOfMonth, endOfMonth));
        return getScheduleVos(schedules, persons, dayTypes);
    }

    @Override
    public void deleteSchedule(String date) {
        DateTime parse = DateUtil.parse(date, "yyyy-MM");
        DateTime beginOfMonth = DateUtil.beginOfMonth(parse);
        DateTime endOfMonth = DateUtil.endOfMonth(parse);
        scheduleMapper.delete(new LambdaQueryWrapper<Schedule>()
                .between(Schedule::getShiftDate, beginOfMonth, endOfMonth));
    }

    @Override
    public List<ScheduleVo> shift(String date) {
        List<Schedule> schedules = scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                .eq(Schedule::getShiftDate, date));
        List<ScheduleVo> scheduleVos = new ArrayList<>();
        for (Schedule schedule : schedules) {
            ScheduleVo scheduleVo = new ScheduleVo();
            scheduleVo.setId(schedule.getId());
            scheduleVo.setShiftId(schedule.getShiftId());
            scheduleVo.setDate(schedule.getShiftDate());
            scheduleVo.setPersonId(schedule.getPersonId());
            scheduleVo.setPerson(personMapper.selectById(schedule.getPersonId()).getRealName());
            scheduleVo.setDayTypeId(schedule.getDayTypeId());
            scheduleVo.setDayTypeName(dayTypeMapper.selectById(schedule.getDayTypeId()).getName());
            scheduleVos.add(scheduleVo);
        }
        return scheduleVos;
    }

    @Override
    public Page<ScheduleVo> getPersonShiftHistoryList(Integer personId, Integer pageNum, Integer pageSize) {
        return scheduleMapper.getPersonShiftHistoryList(personId, new Page<ScheduleVo>(pageNum, pageSize));
    }

    @Override
    public List<PersonStatisticsVo> getPersonStatistics(Integer personId) {
        return scheduleMapper.getPersonStatistics(personId);
    }

    private List<ScheduleVo> getScheduleVos(List<Schedule> schedules, List<Person> persons, List<DayType> dayTypes) {
        List<ScheduleVo> scheduleVos = new ArrayList<>();
        for (Schedule schedule : schedules) {
            ScheduleVo scheduleVo = new ScheduleVo();
            scheduleVo.setId(schedule.getId());
            scheduleVo.setShiftId(schedule.getShiftId());
            scheduleVo.setDate(schedule.getShiftDate());
            scheduleVo.setPersonId(schedule.getPersonId());
            scheduleVo.setPerson(persons.stream().filter(p -> p.getId().equals(schedule.getPersonId())).findFirst().get().getRealName());
            scheduleVo.setDayTypeId(schedule.getDayTypeId());
            scheduleVo.setDayTypeName(dayTypes.stream()
                    .filter(dayType -> dayType.getId().equals(schedule.getDayTypeId())).findFirst().get().getName());
            scheduleVos.add(scheduleVo);
        }
        return scheduleVos;
    }

}
